package com.bringspring.system.scheduletask.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.bringspring.common.base.UserInfo;
import com.bringspring.common.database.data.DataSourceContextHolder;
import com.bringspring.common.database.model.entity.DbLinkEntity;
import com.bringspring.common.database.util.ConnUtil;
import com.bringspring.common.database.model.DataSourceModel;
import com.bringspring.common.model.task.LocalTaskModel;
import com.bringspring.common.util.*;
import com.bringspring.common.util.wxutil.HttpUtil;
import com.bringspring.system.base.entity.DataInterfaceEntity;
import com.bringspring.system.base.service.DataInterfaceService;
import com.bringspring.system.base.service.DblinkService;
import com.bringspring.system.scheduletask.entity.TimeTaskEntity;
import com.bringspring.system.scheduletask.entity.TimeTaskLogEntity;
import com.bringspring.system.scheduletask.model.ContentModel;
import com.bringspring.system.scheduletask.model.TaskParameterModel;
import com.bringspring.system.scheduletask.service.TimeService;
import com.bringspring.system.scheduletask.service.TimeTaskLogService;
import com.bringspring.system.scheduletask.service.TimetaskService;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 开发平台组
 * @version V1.0.0
 * @copyright 股份有限公司
 * @date 2021/3/12 15:31
 */
@Slf4j
@Service
public class TimeServiceImpl implements TimeService {

    @Autowired
    private TimeTaskLogService taskLogService;
    @Autowired
    private TimetaskService taskService;
    @Autowired
    private DataInterfaceService dataInterfaceService;
    @Autowired
    private DblinkService dblinkService;
    @Autowired
    private DataSourceModel dataSourceUtils;
    @Autowired
    private ConcurrentHashMap<String, LocalTaskModel> concurrentHashMap;
    @Autowired
    private UserProvider userProvider;

    @Async
    @Override
    public void storage(ContentModel model, String id, String tenantId, String tenantDbConnectionString, String token) {
        // 切换数据源
        if (StringUtils.isNotEmpty(tenantId)) {
            DataSourceContextHolder.setDatasource(tenantId, tenantDbConnectionString);
        }
        Date startDate = new Date();
        StringBuffer history = new StringBuffer();
        history.append("【" + DateUtil.getNow("+8") + "】" + "【执行开始】 ");
        boolean falg = true;
        String msg = "";
        try {
            // 得到数据接口id
            DataInterfaceEntity entity = dataInterfaceService.getInfo(model.getInterfaceId());
            // 得到SQL语句
            String sql = entity.getQuery();
            // 系统参数替换
            sql = systemParameter(sql, userProvider.get(token));
            // 自定义参数替换
            for (TaskParameterModel parameterModel : model.getParameter()) {
                if (StringUtils.isNotEmpty(parameterModel.getValue())) {
                    sql = sql.replaceAll("\\{" + parameterModel.getField() + "}", parameterModel.getValue());
//                    map.put(parameterModel.getField(), parameterModel.getValue());
                } else {
                    sql = sql.replaceAll("\\{" + parameterModel.getField() + "}", parameterModel.getValue());
//                    map.put(parameterModel.getField(), parameterModel.getDefaultValue());
                }
            }
            DbLinkEntity linkEntity = dblinkService.getInfo(entity.getId());
            @Cleanup Connection conn = null;
            if (linkEntity != null) {
                conn = ConnUtil.getConn(linkEntity);
            } else {
                // 非多租户条件下
                conn = ConnUtil.getConn(dataSourceUtils);
            }
            @Cleanup CallableStatement callStmt = null;
            if (conn != null) {
                callStmt = conn.prepareCall(sql.toString());
//                if (callStmt != null) {
//                    // 处理参数
//                    Map<String, String> map = getUrl(model.getParameter());
//                    for (String field : map.keySet()) {
//                        int i = 1;
//                        callStmt.setString(i + 1, map.get(field));
//                        i++;
//                    }
                    callStmt.execute();
//                }
            }
        } catch (Exception e) {
            falg = false;
            msg = e.getMessage();
        }
        history.append("【" + DateUtil.getNow("+8") + "】");
        history.append(falg ? "【执行成功:存储过程调用成功】 " : "【执行失败:" + msg + "】");
        history.append("【" + DateUtil.getNow("+8") + "】" + "【执行结束】");
        TimeTaskLogEntity baskLog = new TimeTaskLogEntity();
        baskLog.setId(RandomUtil.uuId());
        baskLog.setTaskId(id);
        baskLog.setRunTime(startDate);
        baskLog.setDescription(history.toString());
        baskLog.setRunResult(falg ? 0 : 1);
        taskLogService.save(baskLog);
        TimeTaskEntity entity = taskService.getInfo(id);
        int count = (int)taskLogService.getTaskLogCount(id);
        entity.setRunCount(count);
        entity.setLastModifyTime(startDate);
        entity.setLastRunTime(startDate);
        Date nextTime = DateUtil.getNextCronDate(entity.getExecuteCronExpression(), null);
        entity.setNextRunTime(nextTime);
        taskService.update(id, entity);
    }

    @Async
    @Override
    public void connector(ContentModel model, String id, String token, String tenantId, String tenantDbConnectionString) {
        // 切换数据源
        if (StringUtils.isNotEmpty(tenantId)) {
            DataSourceContextHolder.setDatasource(tenantId, tenantDbConnectionString);
        }
        Date startDate = new Date();
        StringBuffer history = new StringBuffer();
        history.append("【" + DateUtil.getNow("+8") + "】" + "【执行开始】 ");
        // 得到数据接口信息
        DataInterfaceEntity dataInterfaceEntity = dataInterfaceService.getInfo(model.getInterfaceId());
        if (dataInterfaceEntity != null) {
            boolean flag = callHTTP(dataInterfaceEntity, getUrl(model.getParameter()), token);
            history.append("【" + DateUtil.getNow("+8") + "】");
            history.append(flag ? "【执行成功】 " : "【执行失败:无接口】");
            history.append("【" + DateUtil.getNow("+8") + "】" + "【执行结束】");
            TimeTaskLogEntity baskLog = new TimeTaskLogEntity();
            baskLog.setId(RandomUtil.uuId());
            baskLog.setTaskId(id);
            baskLog.setRunTime(startDate);
            baskLog.setDescription(history.toString());
            baskLog.setRunResult(flag ? 0 : 1);
            taskLogService.save(baskLog);
            TimeTaskEntity entity = taskService.getInfo(id);
            int count=(int) taskLogService.getTaskLogCount(id);
            entity.setRunCount(count);
            entity.setLastModifyTime(startDate);
            entity.setLastRunTime(startDate);
            Date nextTime = DateUtil.getNextCronDate(entity.getExecuteCronExpression(), null);
            entity.setNextRunTime(nextTime);
            taskService.update(id, entity);
        }
    }

    @Async
    @Override
    public void localTask(ContentModel model, String id, String token, String tenantId, String tenantDbConnectionString) {
        Date startDate = new Date();
        StringBuffer history = new StringBuffer();
        history.append("【" + DateUtil.getNow("+8") + "】" + "【执行开始】 ");
        // 从容器中取出本地任务信息
        if (concurrentHashMap.containsKey(model.getLocalHostTaskId())) {
            LocalTaskModel taskModel = concurrentHashMap.get(model.getLocalHostTaskId());
            boolean flag = ReflectionUtil.invokeMethodByTask(taskModel.getClz(), taskModel.getMethodName(), taskModel.getParameterType(), taskModel.getParameterValue());
            history.append("【" + DateUtil.getNow("+8") + "】");
            history.append(flag ? "【执行成功】 " : "【执行失败:无接口】");
            history.append("【" + DateUtil.getNow("+8") + "】" + "【执行结束】");
            TimeTaskLogEntity baskLog = new TimeTaskLogEntity();
            baskLog.setId(RandomUtil.uuId());
            baskLog.setTaskId(id);
            baskLog.setRunTime(startDate);
            baskLog.setDescription(history.toString());
            baskLog.setRunResult(flag ? 0 : 1);
            taskLogService.save(baskLog);
            TimeTaskEntity entity = taskService.getInfo(id);
            int count=(int) taskLogService.getTaskLogCount(id);
            entity.setRunCount(count);
            entity.setLastModifyTime(startDate);
            entity.setLastRunTime(startDate);
            Date nextTime = DateUtil.getNextCronDate(entity.getExecuteCronExpression(), null);
            entity.setNextRunTime(nextTime);
            taskService.update(id, entity);
        }
    }

    /**
     * HTTP调用
     *
     * @param entity
     * @return get
     */
    public Boolean callHTTP(DataInterfaceEntity entity, Map<String, String> map, String token) {
        // Post请求拼接参数
        JSONObject jsonObject = new JSONObject();
        String path = entity.getPath();
        // 请求方法
        String requestMethod = entity.getRequestMethod();
        //判断是否为http或https
        if (map != null) {
            // 判断是否为get，get从url上拼接
            if ("6".equals(requestMethod)) {
                path = !path.contains("?") ? path += "?" : path + "&";
                path = parameterHandler(path, map);
                requestMethod = "GET";
            } else {
                for (String field : map.keySet()) {
                    jsonObject.put(field, map.get(field));
                }
                requestMethod = "POST";
            }
        }
        String jsonObjects = jsonObject != null ? jsonObject.toJSONString() : null;
        boolean flag = HttpUtil.httpCronRequest(path, requestMethod, jsonObjects, token);
        return flag;
    }

    /**
     * 处理参数
     *
     * @param path
     * @param map
     * @return
     */
    private String parameterHandler(String path, Map<String, String> map) {
        for (String field : map.keySet()) {
            try {
                String value = URLEncoder.encode(map.get(field), "UTF-8");
                path = path + field + "=" + value + "&";
            } catch (UnsupportedEncodingException e) {
                log.error(e.getMessage());
            }
        }
        return path;
    }

    /**
     * 参数拼接成map
     *
     * @param params 参数
     * @return
     */
    private static Map<String, String> getUrl(List<TaskParameterModel> params) {
        Map<String, String> map = new HashedMap<>(16);
        try {
            for (TaskParameterModel model : params) {
                if (StringUtils.isNotEmpty(model.getValue())) {
                    map.put(model.getField(), model.getValue());
                } else {
                    map.put(model.getField(), model.getDefaultValue());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("url错误{}", e.getMessage());
        }
        return map;
    }

    /**
     * 处理sql参数
     *
     * @param sql
     * @return
     */
    private String systemParameter(String sql, UserInfo userInfo) {
        if (sql.contains("@user") && StringUtils.isNotEmpty(userInfo.getUserId())) {
            String userId = userInfo.getUserId();
            sql = sql.replaceAll("@user", "'" + userId + "'");
        }
        if (sql.contains("@department") && StringUtils.isNotEmpty(userInfo.getDepartmentId())) {
            String departmentId = userInfo.getDepartmentId();
            sql = sql.replaceAll("@department", "'" + departmentId + "'");
        }
        if (sql.contains("@organize") && StringUtils.isNotEmpty(userInfo.getOrganizeId())) {
            String organizeId = userInfo.getOrganizeId();
            sql = sql.replaceAll("@organize", "'" + organizeId + "'");
        }
        if (sql.contains("@postion") && StringUtils.isNotEmpty(userInfo.getPositionIds())) {
            String positionId = userInfo.getPositionIds() != null ? userInfo.getPositionIds()[0] : null;
            sql = sql.replaceAll("@postion", "'" + positionId + "'");
        }
        return sql;
    }
}
